﻿using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Media;

using CsharpPoker.Core;

namespace CsharpPoker
{
    /// <summary>
    /// The `StartScene` is just an option menu with a pertty bg and some flashy text related to CSP.
    /// </summary>
    public class TexasHoldemScene : GameScene
    {
        // TexasHoldemScene Data ------------------------------------------- //

        // Input
        protected Input input;

        // Misc
        protected TextMenuComponent endMenu; // displayed at end of texas holdem game

        // Gui Stuff
        protected SpriteBatch spriteBatch = null;
        Rectangle screen = new Rectangle(0, 0, 0, 0);

        Color backgroundColor;

        Texture2D cardBack;
        Rectangle cardRect = new Rectangle(0, 0, 50, 70);

        Texture2D cardSheet;
        
        // GUI components
        Button checkButton;
        Button foldButton;
        Mouse  mouse;

        // fonts
        SpriteFont font, largeFont;

        // scene manager that contains us.
        SceneManager sceneManager;

        // reference to the Game this scene is taking place in.
        Game game;

        // game objects
        TexasHoldemEngine texasHoldemEngine;

        // Holdem Ctors/Dtors/etc... --------------------------------------- //

        // Constructor
        public TexasHoldemScene(Game game, SceneManager sceneManager)
            : base(game)
        {
            this.game = game;
            this.sceneManager = sceneManager;

            // Get the audio library
            //audio = (AudioLibrary) Game.Services.GetService(typeof(AudioLibrary));
            input = new Input();

            texasHoldemEngine = new TexasHoldemEngine();

        }

        // Holdem Scene functionality -------------------------------------- //

        /// <summary>
        /// Show the start scene
        /// </summary>
        public override void Show()
        {

            // Put the menu centered in screen
            endMenu.Position = new Vector2((Game.Window.ClientBounds.Width - endMenu.Width) / 2, 75);

            endMenu.Visible = false;
            endMenu.Enabled = false;
            
            base.Show();
        }

        /// <summary>
        /// Hide the start scene
        /// </summary>
        public override void Hide()
        {
            MediaPlayer.Stop();
            base.Hide();
        }

        public override void Input()
        {
            if (checkButton.State == Button.States.justReleased)
            {
                texasHoldemEngine.Player1.Action = TexasHoldemEngine.PlayerActions.check;
            }
            else if (foldButton.State == Button.States.justReleased)
            {
                texasHoldemEngine.Player1.Action = TexasHoldemEngine.PlayerActions.fold;
            }
            else
            {
                texasHoldemEngine.Player1.Action = TexasHoldemEngine.PlayerActions.none;
            }

            if (input.CheckEnter())
            {
                if (endMenu.Visible && endMenu.Enabled)
                {
                    switch (endMenu.SelectedIndex)
                    {
                        case 0:
                            RestartScene();
                            sceneManager.ShowScene(sceneManager.StartScene);
                            break;
                        case 1:
                            Game.Exit();
                            break;
                    }
                }
            }

            base.Input();
        }

        public override void RestartScene()
        {
            texasHoldemEngine.Setup();
            texasHoldemEngine.Preflop();
        }

        // Holdem DrawingComponent functionality --------------------------- /.
        
        public override void Initialize()
        {
            base.Initialize();
        }
        
        protected override void LoadContent()
        {
            RefreshScreenDimension();

            backgroundColor = Color.ForestGreen;

            // load textures
            cardBack    = Game.Content.Load<Texture2D>("Card-Back-05");
            cardSheet   = Game.Content.Load<Texture2D>("classic_13x4x560x780");

            // create mouse. it will be added to components last so it renders on top of everything.
            mouse = new Mouse(game, "spadeCursor2");

            // load gui components
            checkButton = new Button(game, mouse, "checkButton");
            Components.Add(checkButton);
            foldButton = new Button(game, mouse, "foldButton");
            Components.Add(foldButton);

            Components.Add(mouse);

            // load fonts
            font = Game.Content.Load<SpriteFont>("menuSmall");
            largeFont = Game.Content.Load<SpriteFont>("menuLarge");

            // Create the end of game menu
            Texture2D dummyTexture = new Texture2D(GraphicsDevice, 1, 1);
            dummyTexture.SetData(new Color[] { backgroundColor });
            string[] items = { "Play Again", "Quit" };
            endMenu = new TextMenuComponent(game, font, largeFont, dummyTexture);
            endMenu.DrawingBackground = true;
            endMenu.SetMenuItems(items);
            Components.Add(endMenu);

            // Get the current spritebatch
            spriteBatch = (SpriteBatch)Game.Services.GetService(typeof(SpriteBatch));
;
 
            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            texasHoldemEngine.Run();            

            base.Update(gameTime);
        }

        // holdem GUI and drawing methods ---------------------------------- //
        
        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(backgroundColor);

            RefreshScreenDimension();

            DrawPlayerHud();

            DrawDeck();
            DrawPlayerCards();
            DrawCommunityCards();

            // has the game ended?
            if (texasHoldemEngine.State == TexasHoldemEngine.States.end)
            {
                endMenu.Visible = true;
                endMenu.Enabled = true;
            }

            base.Draw(gameTime);
        }
        
        void RefreshScreenDimension()
        {
            screen.Width = Game.GraphicsDevice.Viewport.Width;
            screen.Height = Game.GraphicsDevice.Viewport.Height;
        }

        void DrawCard(Vector2 position, Rectangle rect, int deckIdx)
        {
            // calculate source rectangle for the card face.
            int row    = deckIdx / 13;
            int column = deckIdx % 13;
            int x = column * 560;
            int y = row * 780;


            Rectangle srcRect = new Rectangle(x, y, 560, 780);

            // draw small squares to represent cards, lol
            rect.X = (int)position.X;
            rect.Y = (int)position.Y;
            spriteBatch.Draw(cardSheet, rect, srcRect, Color.White);

            // write text on the cards
            //string cardText = texasHoldemEngine.Deck[deckIdx].ToString();

            // Draw the text shadow
            //spriteBatch.DrawString(font, cardText, new Vector2(position.X + 1, position.Y + 1), Color.Black);
            // Draw the text item
            //spriteBatch.DrawString(font, cardText, new Vector2(position.X, position.Y + 1), Color.AliceBlue);
        }

        void DrawFlippedCard(Vector2 position, Rectangle rect)
        {
            // draw small squares to represent cards, lol
            spriteBatch.Draw(cardBack, position, rect, Color.White);
        }

        void DrawDeck()
        {
            // rect and pos for the cards.
            Rectangle rect = new Rectangle(0, 0, 50, 70);
            Vector2 position = new Vector2(0, 10);

            // font for the cards.
            //Color color = Color.AntiqueWhite;

            // figure out a nice way to display the cards. I want them to be clearly visible, yet not take up much space.
            // so a couple of row near the top of the screen.

            // figure out least rows possible;
            int rows = 4;

            // how many card per a row?
            int cardPerRow = 52 / rows; // 13

            int deckIdx = texasHoldemEngine.DeckIdx; // DeckIdx implicitly gives us the state of the holdem game.

            for (int y = 0; y < rows; y++)
            {
                for (int x = 0; (x < cardPerRow) && (deckIdx < 52); x++, deckIdx++)
                {
                    DrawCard(position, rect, texasHoldemEngine.Deck[deckIdx]);
                    //DrawFlippedCard(position, rect);

                    position.X += rect.Width + 4;
                }
                position.X = 0;
                position.Y += rect.Height + 4;
            }
            
        }

        Rectangle positionOfPlayersCards;

        void DrawPlayerCards()
        {
            // rect and pos for the cards.
            Rectangle rect = new Rectangle(0, 0, 50, 70);

            positionOfPlayersCards = new Rectangle(screen.Width/2 - (rect.Width*2 + 4)/2, 
                                                   screen.Height - 100, 50, 70);
            Vector2 position = new Vector2(positionOfPlayersCards.X, positionOfPlayersCards.Y);

            // draw first player's hole cards
            if (texasHoldemEngine.DeckIdx >= 2)
            {
                for (int i = 0; i < 2; i++)
                {
                    DrawCard(position, rect, texasHoldemEngine.Player1.Cards[i]);

                    position.X += rect.Width + 4;
                }
            }
            positionOfPlayersCards.Width = (int)(position.X - positionOfPlayersCards.X);
        }

        void DrawFlop(Vector2 position)
        {
            int indexOfFlop = 2 + 1;

            // have first 3 community cards been dealt?
            if (texasHoldemEngine.DeckIdx >= indexOfFlop + 3)
            {
                for (int i = 0; i < 3; i++)
                {
                    DrawCard(position, cardRect, texasHoldemEngine.Deck[indexOfFlop + i]);

                    position.X += cardRect.Width + 4;
                }
            }
        }

        // position of first card in the community cards
        void DrawTurn(Vector2 position)
        {  
            //                holeCards     burn     flop      burn
            int indexOfTurn =    (2)     +  (1)   +  (3)    +   (1)   ;

            position.X += cardRect.Width * 3 + 4 * 3;
            DrawCard(position, cardRect, texasHoldemEngine.Deck[indexOfTurn]);
        }

        void DrawRiver(Vector2 position)
        {
            //                holeCards     burn     flop      burn    turn     burn
            int indexOfRiver = (2)        +  (1)   +   (3)  +    (1)    + (1) + (1);

            position.X += cardRect.Width * 4 + 4 * 4;
            DrawCard(position, cardRect, texasHoldemEngine.Deck[indexOfRiver]);
        }

        void DrawCommunityCards()
        {
            int count = 0; // number of community cards thats have been dealt.
            int space = 4; // space between cards

            for (int i = 0; i < 5; ++i)
            {
                if (texasHoldemEngine.CommunityCard[i] == TexasHoldemEngine.NoCard)
                    break;
                else
                    count++;
            }

            if (count == 0)
                return;
           
            int center = screen.Width / 2; // middle of screen on the x-axis
            
            // figure out imageWidth and horizontal shift it so the image center is aligned with the x-axis center.                        
            int imageWidth = cardRect.Width * count + space * (count - 1);

            Vector2 position = new Vector2(center - imageWidth / 2, screen.Height - 250);

            DrawFlop(position);

            if (count >= 4)
                DrawTurn(position);
            if (count >= 5)
                DrawRiver(position);

            position.X -= cardRect.Width*2;
            position.Y += space * 4;

            DrawBurns(position);
        }

        void DrawBurns(Vector2 position)
        {
            for (int i = 0; i < texasHoldemEngine.Burns.Count; i++)
            {
                DrawCard(position, cardRect, texasHoldemEngine.Burns[i]);
                position.Y += 16;
            }
        }

        void DrawPlayerHud()
        {
            // render Check button
            checkButton.Position = new Vector2(positionOfPlayersCards.X + positionOfPlayersCards.Width + 4,
                                               positionOfPlayersCards.Y);

            foldButton.Position = new Vector2(positionOfPlayersCards.X - (foldButton.Width + 4),
                                               positionOfPlayersCards.Y);
            //foldButton.
            //checkButton.Position.X += cardRec

            // render Fold button
        }
    }
}